#include "alfaBetaWithMemory.h"
#include "othello_cut.h"
#include "hashMap.h"

#include <iostream>
#include <map>

#include <stdio.h>
#include <stdlib.h>

using namespace std;

#include <limits.h>

#define MAX(s,t)      ((s)>(t)?(s):(t))
#define MIN(s,t)      ((s)<(t)?(s):(t))

alfaBetaWithMemory::alfaBetaWithMemory()
{
    nodGen = 0;
}

int alfaBetaWithMemory::AlphaBetaWithMemory(Nodo *nodo, int a, int b, int profundidad, bool juegaNegro) {
    hash_t::iterator lk;
    int alpha = a, beta = b, g;
    limits L;
    
    
    if ( !( (lk = map.find(nodo->estado)) == map.end() ) ) {
        L = lk->second;
        if (L.lowerbound >= b) return L.lowerbound;
        if (L.upperbound <= a) return L.upperbound;

        a = MAX(a, L.lowerbound);
        b = MIN(b, L.upperbound);
    }
    
    
    if (nodo->esTerminal() || (profundidad == 0)) {
        g = nodo->Valor();
    } else if(juegaNegro) {
        g = INT_MIN;
        
        Nodo::Iterador it(nodo);
        Nodo hijo;
        
        --profundidad;
        
        while (it.Siguiente(&hijo) && g < beta) {
            nodGen++;
            g = MAX(g, AlphaBetaWithMemory(&hijo, a, beta, profundidad, false));
            a = MAX(a,g);
        }
        
    } else {
        g = INT_MAX;
        
        Nodo::Iterador it(nodo);
        Nodo hijo;
        
        --profundidad;
        
        while (it.Siguiente(&hijo) && g > alpha) {
            nodGen++;
            g = MIN(g, AlphaBetaWithMemory(&hijo, alpha, b, profundidad, true));
            b = MIN(b,g);
        }
    }

    if (g <= alpha) {
        L.upperbound = g;
    } else if (g > alpha && g < beta) {
        L.lowerbound = g;
        L.upperbound = g;
    } else if (g >= beta) {
        L.lowerbound = g;
    }

    map[nodo->estado] = L;

    return g;
}


int alfaBetaWithMemory::NodGen() const{
    return nodGen;
}



